#include "wx/wxprec.h"
#include "wx/aui/framemanager.h"
#include "wx/aui/dockart.h"
#include <gtk/gtk.h>
#include "wx/gtk/win_gtk.h"
#include "wx/renderer.h"

unsigned char wxAuiBlendColour( unsigned char fg, unsigned char bg, double alpha ) {
  double result = bg + ( alpha * ( fg - bg ) );
  if( result < 0.0 ) {
    result = 0.0;
  }
  if( result > 255 ) {
    result = 255;
  }
  return ( unsigned char )result;
}

wxColor wxAuiStepColour( const wxColor& c, int ialpha ) {
  if( ialpha == 100 ) {
    return c;
  }
  unsigned char r = c.Red(),
                g = c.Green(),
                b = c.Blue();
  unsigned char bg;
  ialpha = wxMin( ialpha, 200 );
  ialpha = wxMax( ialpha, 0 );
  double alpha = ( ( double )( ialpha - 100.0 ) ) / 100.0;
  if( ialpha > 100 ) {
    bg = 255;
    alpha = 1.0 - alpha;
  } else {
    bg = 0;
    alpha += 1.0;
  }
  r = wxAuiBlendColour( r, bg, alpha );
  g = wxAuiBlendColour( g, bg, alpha );
  b = wxAuiBlendColour( b, bg, alpha );
  return wxColour( r, g, b );
}


wxColor wxAuiLightContrastColour( const wxColour& c ) {
  int amount = 120;
  if( c.Red() < 128 && c.Green() < 128 && c.Blue() < 128 ) {
    amount = 160;
  }
  return wxAuiStepColour( c, amount );
}

wxBitmap wxAuiBitmapFromBits( const unsigned char bits[], int w, int h, const wxColour& color ) {
  wxImage img = wxBitmap( ( const char* )bits, w, h ).ConvertToImage();
  img.Replace( 0, 0, 0, 123, 123, 123 );
  img.Replace( 255, 255, 255, color.Red(), color.Green(), color.Blue() );
  img.SetMaskColour( 123, 123, 123 );
  return wxBitmap( img );
}


static void DrawGradientRectangle( wxDC& dc, const wxRect& rect, const wxColour& start_color, const wxColour& end_color, int direction ) {
  int rd, gd, bd, high = 0;
  rd = end_color.Red() - start_color.Red();
  gd = end_color.Green() - start_color.Green();
  bd = end_color.Blue() - start_color.Blue();
  if( direction == wxAUI_GRADIENT_VERTICAL ) {
    high = rect.GetHeight() - 1;
  } else {
    high = rect.GetWidth() - 1;
  }
  for( int i = 0; i <= high; ++i ) {
    int r, g, b;
    r = start_color.Red() + ( high <= 0 ? 0 : ( ( ( i * rd * 100 ) / high ) / 100 ) );
    g = start_color.Green() + ( high <= 0 ? 0 : ( ( ( i * gd * 100 ) / high ) / 100 ) );
    b = start_color.Blue() + ( high <= 0 ? 0 : ( ( ( i * bd * 100 ) / high ) / 100 ) );
    wxPen p( wxColor( ( unsigned char )r, ( unsigned char )g, ( unsigned char )b ) );
    dc.SetPen( p );
    if( direction == wxAUI_GRADIENT_VERTICAL ) {
      dc.DrawLine( rect.x, rect.y + i, rect.x + rect.width, rect.y + i );
    } else {
      dc.DrawLine( rect.x + i, rect.y, rect.x + i, rect.y + rect.height );
    }
  }
}

wxString wxAuiChopText( wxDC& dc, const wxString& text, int max_size ) {
  wxCoord x, y;
  dc.GetTextExtent( text, &x, &y );
  if( x <= max_size ) {
    return text;
  }
  size_t i, len = text.Length();
  size_t last_good_length = 0;
  for( i = 0; i < len; ++i ) {
    wxString s = text.Left( i );
    s += wxT( "..." );
    dc.GetTextExtent( s, &x, &y );
    if( x > max_size ) {
      break;
    }
    last_good_length = i;
  }
  wxString ret = text.Left( last_good_length );
  ret += wxT( "..." );
  return ret;
}

wxAuiDefaultDockArt::wxAuiDefaultDockArt() {
  wxColor base_colour = wxSystemSettings::GetColour( wxSYS_COLOUR_3DFACE );
  if( ( 255 - base_colour.Red() ) + ( 255 - base_colour.Green() ) + ( 255 - base_colour.Blue() ) < 60 ) {
    base_colour = wxAuiStepColour( base_colour, 92 );
  }
  m_base_colour = base_colour;
  wxColor darker1_colour = wxAuiStepColour( base_colour, 85 );
  wxColor darker2_colour = wxAuiStepColour( base_colour, 75 );
  wxColor darker3_colour = wxAuiStepColour( base_colour, 60 );
  wxColor darker4_colour = wxAuiStepColour( base_colour, 50 );
  wxColor darker5_colour = wxAuiStepColour( base_colour, 40 );
  m_active_caption_colour = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
  m_active_caption_gradient_colour = wxAuiLightContrastColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
  m_active_caption_text_colour = *wxBLACK;  // 激活焦点
  m_inactive_caption_colour = darker1_colour;
  m_inactive_caption_gradient_colour = wxAuiStepColour( base_colour, 97 );
  m_inactive_caption_text_colour = wxColor(0x78,0x78,0x78);  // 失去焦点
  m_sash_brush = wxBrush( base_colour );
  m_background_brush = wxBrush( base_colour );
  m_gripper_brush = wxBrush( base_colour );
  m_border_pen = wxPen( darker2_colour );
  m_gripper_pen1 = wxPen( darker5_colour );
  m_gripper_pen2 = wxPen( darker3_colour );
  m_gripper_pen3 = *wxWHITE_PEN;
  m_caption_font = wxFont( 9, wxDEFAULT, wxNORMAL, wxNORMAL, FALSE );
  static unsigned char close_bits[] = {
    0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
    0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
    0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  };
  static unsigned char maximize_bits[] = {
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xf7, 0xf7, 0x07, 0xf0,
    0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0x07, 0xf0,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  };
  static unsigned char restore_bits[] = {
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xf0, 0x1f, 0xf0, 0xdf, 0xf7,
    0x07, 0xf4, 0x07, 0xf4, 0xf7, 0xf5, 0xf7, 0xf1, 0xf7, 0xfd, 0xf7, 0xfd,
    0x07, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  };
  static unsigned char pin_bits[] = {
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfc, 0xdf, 0xfc, 0xdf, 0xfc,
    0xdf, 0xfc, 0xdf, 0xfc, 0xdf, 0xfc, 0x0f, 0xf8, 0x7f, 0xff, 0x7f, 0xff,
    0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  };
  m_inactive_close_bitmap = wxAuiBitmapFromBits( close_bits, 16, 16, m_inactive_caption_text_colour );
  m_active_close_bitmap = wxAuiBitmapFromBits( close_bits, 16, 16, m_active_caption_text_colour );
  m_inactive_maximize_bitmap = wxAuiBitmapFromBits( maximize_bits, 16, 16, m_inactive_caption_text_colour );
  m_active_maximize_bitmap = wxAuiBitmapFromBits( maximize_bits, 16, 16, m_active_caption_text_colour );
  m_inactive_restore_bitmap = wxAuiBitmapFromBits( restore_bits, 16, 16, m_inactive_caption_text_colour );
  m_active_restore_bitmap = wxAuiBitmapFromBits( restore_bits, 16, 16, m_active_caption_text_colour );
  m_inactive_pin_bitmap = wxAuiBitmapFromBits( pin_bits, 16, 16, m_inactive_caption_text_colour );
  m_active_pin_bitmap = wxAuiBitmapFromBits( pin_bits, 16, 16, m_active_caption_text_colour );
  m_sash_size = wxRendererNative::Get().GetSplitterParams( NULL ).widthSash;
  m_caption_size = 17;
  m_border_size = 1;
  m_button_size = 14;
  m_gripper_size = 9;
  m_gradient_type = wxAUI_GRADIENT_VERTICAL;
}

int wxAuiDefaultDockArt::GetMetric( int id ) {
  switch( id ) {
    case wxAUI_DOCKART_SASH_SIZE:
      return m_sash_size;
    case wxAUI_DOCKART_CAPTION_SIZE:
      return m_caption_size;
    case wxAUI_DOCKART_GRIPPER_SIZE:
      return m_gripper_size;
    case wxAUI_DOCKART_PANE_BORDER_SIZE:
      return m_border_size;
    case wxAUI_DOCKART_PANE_BUTTON_SIZE:
      return m_button_size;
    case wxAUI_DOCKART_GRADIENT_TYPE:
      return m_gradient_type;
    default:
      wxFAIL_MSG( wxT( "Invalid Metric Ordinal" ) );
      break;
  }
  return 0;
}

void wxAuiDefaultDockArt::SetMetric( int id, int new_val ) {
  switch( id ) {
    case wxAUI_DOCKART_SASH_SIZE:
      m_sash_size = new_val;
      break;
    case wxAUI_DOCKART_CAPTION_SIZE:
      m_caption_size = new_val;
      break;
    case wxAUI_DOCKART_GRIPPER_SIZE:
      m_gripper_size = new_val;
      break;
    case wxAUI_DOCKART_PANE_BORDER_SIZE:
      m_border_size = new_val;
      break;
    case wxAUI_DOCKART_PANE_BUTTON_SIZE:
      m_button_size = new_val;
      break;
    case wxAUI_DOCKART_GRADIENT_TYPE:
      m_gradient_type = new_val;
      break;
    default:
      wxFAIL_MSG( wxT( "Invalid Metric Ordinal" ) );
      break;
  }
}

wxColour wxAuiDefaultDockArt::GetColour( int id ) {
  switch( id ) {
    case wxAUI_DOCKART_BACKGROUND_COLOUR:
      return m_background_brush.GetColour();
    case wxAUI_DOCKART_SASH_COLOUR:
      return m_sash_brush.GetColour();
    case wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR:
      return m_inactive_caption_colour;
    case wxAUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR:
      return m_inactive_caption_gradient_colour;
    case wxAUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR:
      return m_inactive_caption_text_colour;
    case wxAUI_DOCKART_ACTIVE_CAPTION_COLOUR:
      return m_active_caption_colour;
    case wxAUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR:
      return m_active_caption_gradient_colour;
    case wxAUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR:
      return m_active_caption_text_colour;
    case wxAUI_DOCKART_BORDER_COLOUR:
      return m_border_pen.GetColour();
    case wxAUI_DOCKART_GRIPPER_COLOUR:
      return m_gripper_brush.GetColour();
    default:
      wxFAIL_MSG( wxT( "Invalid Metric Ordinal" ) );
      break;
  }
  return wxColour();
}

void wxAuiDefaultDockArt::SetColour( int id, const wxColor& colour ) {
  switch( id ) {
    case wxAUI_DOCKART_BACKGROUND_COLOUR:
      m_background_brush.SetColour( colour );
      break;
    case wxAUI_DOCKART_SASH_COLOUR:
      m_sash_brush.SetColour( colour );
      break;
    case wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR:
      m_inactive_caption_colour = colour;
      break;
    case wxAUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR:
      m_inactive_caption_gradient_colour = colour;
      break;
    case wxAUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR:
      m_inactive_caption_text_colour = colour;
      break;
    case wxAUI_DOCKART_ACTIVE_CAPTION_COLOUR:
      m_active_caption_colour = colour;
      break;
    case wxAUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR:
      m_active_caption_gradient_colour = colour;
      break;
    case wxAUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR:
      m_active_caption_text_colour = colour;
      break;
    case wxAUI_DOCKART_BORDER_COLOUR:
      m_border_pen.SetColour( colour );
      break;
    case wxAUI_DOCKART_GRIPPER_COLOUR:
      m_gripper_brush.SetColour( colour );
      m_gripper_pen1.SetColour( wxAuiStepColour( colour, 40 ) );
      m_gripper_pen2.SetColour( wxAuiStepColour( colour, 60 ) );
      break;
    default:
      wxFAIL_MSG( wxT( "Invalid Metric Ordinal" ) );
      break;
  }
}

void wxAuiDefaultDockArt::SetFont( int id, const wxFont& font ) {
  if( id == wxAUI_DOCKART_CAPTION_FONT ) {
    m_caption_font = font;
  }
}

wxFont wxAuiDefaultDockArt::GetFont( int id ) {
  if( id == wxAUI_DOCKART_CAPTION_FONT ) {
    return m_caption_font;
  }
  return wxNullFont;
}

void wxAuiDefaultDockArt::DrawSash( wxDC& dc, wxWindow *window, int orientation, const wxRect& rect ) {
  dc.SetPen( *wxTRANSPARENT_PEN );
  dc.SetBrush( m_sash_brush );
  dc.DrawRectangle( rect.x, rect.y, rect.width, rect.height );
  if( !window ) {
    return;
  }
  if( !window->m_wxwindow ) {
    return;
  }
  if( !GTK_PIZZA( window->m_wxwindow )->bin_window ) {
    return;
  }
  gtk_paint_handle ( window->m_wxwindow->style, GTK_PIZZA( window->m_wxwindow )->bin_window, GTK_STATE_NORMAL,
    GTK_SHADOW_NONE, NULL, window->m_wxwindow, "paned", rect.x, rect.y, rect.width, rect.height,
    ( orientation == wxVERTICAL ) ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
  );
}


void wxAuiDefaultDockArt::DrawBackground( wxDC& dc, wxWindow *( window ), int, const wxRect& rect ) {
  dc.SetPen( *wxTRANSPARENT_PEN );
  dc.SetBrush( m_background_brush );
  dc.DrawRectangle( rect.x, rect.y, rect.width, rect.height );
}

void wxAuiDefaultDockArt::DrawBorder( wxDC& dc, wxWindow *( window ), const wxRect& _rect, wxAuiPaneInfo& pane ) {
  dc.SetPen( m_border_pen );
  dc.SetBrush( *wxTRANSPARENT_BRUSH );
  wxRect rect = _rect;
  int i, border_width = GetMetric( wxAUI_DOCKART_PANE_BORDER_SIZE );
  if( pane.IsToolbar() ) {
    for( i = 0; i < border_width; ++i ) {
      dc.SetPen( *wxWHITE_PEN );
      dc.DrawLine( rect.x, rect.y, rect.x + rect.width, rect.y );
      dc.DrawLine( rect.x, rect.y, rect.x, rect.y + rect.height );
      dc.SetPen( m_border_pen );
      dc.DrawLine( rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1 );
      dc.DrawLine( rect.x + rect.width - 1, rect.y, rect.x + rect.width - 1, rect.y + rect.height );
      rect.Deflate( 1 );
    }
  } else {
    for( i = 0; i < border_width; ++i ) {
      dc.DrawRectangle( rect.x, rect.y, rect.width, rect.height );
      rect.Deflate( 1 );
    }
  }
}


void wxAuiDefaultDockArt::DrawCaptionBackground( wxDC& dc, const wxRect& rect, bool active ) {
  if( m_gradient_type == wxAUI_GRADIENT_NONE ) {
    if( active ) {
      dc.SetBrush( wxBrush( m_active_caption_colour ) );
    } else {
      dc.SetBrush( wxBrush( m_inactive_caption_colour ) );
    }
    dc.DrawRectangle( rect.x, rect.y, rect.width, rect.height );
  } else {
    if( active ) {
      DrawGradientRectangle( dc, rect, m_active_caption_gradient_colour, m_active_caption_colour, m_gradient_type );
    } else {
      DrawGradientRectangle( dc, rect, m_inactive_caption_colour, m_inactive_caption_gradient_colour, m_gradient_type );
    }
  }
}


void wxAuiDefaultDockArt::DrawCaption( wxDC& dc, wxWindow *( window ), const wxString& text, const wxRect& rect, wxAuiPaneInfo& pane ) {
  dc.SetPen( *wxTRANSPARENT_PEN );
  dc.SetFont( m_caption_font );
  DrawCaptionBackground( dc, rect, ( pane.state & wxAuiPaneInfo::optionActive ) ? true : false );
  if( pane.state & wxAuiPaneInfo::optionActive ) {
    dc.SetTextForeground( m_active_caption_text_colour );
  } else {
    dc.SetTextForeground( m_inactive_caption_text_colour );
  }
  wxCoord w, h;
  dc.GetTextExtent( wxT( "ABCDEFHXfgkj" ), &w, &h );
  wxRect clip_rect = rect;
  clip_rect.width -= 3; // text offset
  clip_rect.width -= 2; // button padding
  if( pane.HasCloseButton() ) {
    clip_rect.width -= m_button_size;
  }
  if( pane.HasPinButton() ) {
    clip_rect.width -= m_button_size;
  }
  if( pane.HasMaximizeButton() ) {
    clip_rect.width -= m_button_size;
  }
  wxString draw_text = wxAuiChopText( dc, text, clip_rect.width );
  dc.SetClippingRegion( clip_rect );
  dc.DrawText( draw_text, rect.x + 3, rect.y + ( rect.height / 2 ) - ( h / 2 ) - 1 );
  dc.DestroyClippingRegion();
}

void wxAuiDefaultDockArt::DrawGripper( wxDC& dc, wxWindow *( window ),
                                       const wxRect& rect,
                                       wxAuiPaneInfo& pane ) {
  dc.SetPen( *wxTRANSPARENT_PEN );
  dc.SetBrush( m_gripper_brush );
  dc.DrawRectangle( rect.x, rect.y, rect.width, rect.height );
  if( !pane.HasGripperTop() ) {
    int y = 5;
    while( 1 ) {
      dc.SetPen( m_gripper_pen1 );
      dc.DrawPoint( rect.x + 3, rect.y + y );
      dc.SetPen( m_gripper_pen2 );
      dc.DrawPoint( rect.x + 3, rect.y + y + 1 );
      dc.DrawPoint( rect.x + 4, rect.y + y );
      dc.SetPen( m_gripper_pen3 );
      dc.DrawPoint( rect.x + 5, rect.y + y + 1 );
      dc.DrawPoint( rect.x + 5, rect.y + y + 2 );
      dc.DrawPoint( rect.x + 4, rect.y + y + 2 );
      y += 4;
      if( y > rect.GetHeight() - 5 ) {
        break;
      }
    }
  } else {
    int x = 5;
    while( 1 ) {
      dc.SetPen( m_gripper_pen1 );
      dc.DrawPoint( rect.x + x, rect.y + 3 );
      dc.SetPen( m_gripper_pen2 );
      dc.DrawPoint( rect.x + x + 1, rect.y + 3 );
      dc.DrawPoint( rect.x + x, rect.y + 4 );
      dc.SetPen( m_gripper_pen3 );
      dc.DrawPoint( rect.x + x + 1, rect.y + 5 );
      dc.DrawPoint( rect.x + x + 2, rect.y + 5 );
      dc.DrawPoint( rect.x + x + 2, rect.y + 4 );
      x += 4;
      if( x > rect.GetWidth() - 5 ) {
        break;
      }
    }
  }
}

void wxAuiDefaultDockArt::DrawPaneButton( wxDC& dc, wxWindow *( window ),
    int button,
    int button_state,
    const wxRect& _rect,
    wxAuiPaneInfo& pane ) {
  wxBitmap bmp;
  if( !( &pane ) ) {
    return;
  }
  switch( button ) {
    default:
    case wxAUI_BUTTON_CLOSE:
      if( pane.state & wxAuiPaneInfo::optionActive ) {
        bmp = m_active_close_bitmap;
      } else
      { bmp = m_inactive_close_bitmap; }
      break;
    case wxAUI_BUTTON_PIN:
      if( pane.state & wxAuiPaneInfo::optionActive ) {
        bmp = m_active_pin_bitmap;
      } else
      { bmp = m_inactive_pin_bitmap; }
      break;
    case wxAUI_BUTTON_MAXIMIZE_RESTORE:
      if( pane.IsMaximized() ) {
        if( pane.state & wxAuiPaneInfo::optionActive ) {
          bmp = m_active_restore_bitmap;
        } else
        { bmp = m_inactive_restore_bitmap; }
      } else {
        if( pane.state & wxAuiPaneInfo::optionActive ) {
          bmp = m_active_maximize_bitmap;
        } else
        { bmp = m_inactive_maximize_bitmap; }
      }
      break;
  }
  wxRect rect = _rect;
  int old_y = rect.y;
  rect.y = rect.y + ( rect.height / 2 ) - ( bmp.GetHeight() / 2 );
  rect.height = old_y + rect.height - rect.y - 1;
  if( button_state == wxAUI_BUTTON_STATE_PRESSED ) {
    rect.x++;
    rect.y++;
  }
  if( button_state == wxAUI_BUTTON_STATE_HOVER ||
      button_state == wxAUI_BUTTON_STATE_PRESSED ) {
    if( pane.state & wxAuiPaneInfo::optionActive ) {
      dc.SetBrush( wxBrush( wxAuiStepColour( m_active_caption_colour, 120 ) ) );
      dc.SetPen( wxPen( wxAuiStepColour( m_active_caption_colour, 70 ) ) );
    } else {
      dc.SetBrush( wxBrush( wxAuiStepColour( m_inactive_caption_colour, 120 ) ) );
      dc.SetPen( wxPen( wxAuiStepColour( m_inactive_caption_colour, 70 ) ) );
    }
    dc.DrawRectangle( rect.x, rect.y, 15, 15 );
  }
  dc.DrawBitmap( bmp, rect.x, rect.y, true );
}
